package com.ttx.proxy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author TimFruit
 * @date 2019/8/8 8:37
 */

public class ProxyServer {
    public static  final Logger logger= LoggerFactory.getLogger(ProxyServer.class);
    
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket=null;
        
        
        try {
            int port=19999;
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(port));
            Socket socket = null;
            ExecutorService executorService = Executors.newCachedThreadPool();
            while (true) {
                logger.info("本代理服务监听端口为{}, 等待请求, 不支持https ...", port);
                socket = serverSocket.accept();
                logger.info("代理服务收到一个请求...");
                executorService.submit(new TransSocket(socket));
            }
        }catch (Exception e){
            if(serverSocket!=null){
                serverSocket.close();
            }
        }
    }
    
    
    private static class TransSocket implements Runnable{
        private Socket oriSocket;
        public TransSocket(Socket socket) {
            this.oriSocket = socket;
        }
        @Override
        public void run() {
            try{
                logger.info("读取请求...");
                InputStream is=oriSocket.getInputStream();
                ByteArrayOutputStream bos=new ByteArrayOutputStream();
                int b=-1;
                
                while((b=is.read())>-1){
                    bos.write(b);
                    if(is.available() == 0){
                        break;
                    }
                }
                if(logger.isDebugEnabled()){
                    logger.debug("输出请求...");
                    logger.debug(bos.toString());
                }
                
                
                
                
                logger.info("代理请求...");
                byte[] response=proxyRequest(bos.toByteArray() );
                
                
                OutputStream os=oriSocket.getOutputStream();
                os.write(response);
                os.flush();
                
                if(logger.isDebugEnabled()){
                    logger.info("代理请求后的响应为：{}", new String(response));
                }
                logger.info("完成...");
                
                
                logger.info("关闭连接");
                oriSocket.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        
        
        
        private byte[] proxyRequest(byte[] request) throws IOException {

            // 查找真正的服务地址 
            String realHost=null;
            int realPort=-1;
            
            ByteArrayInputStream bais=new ByteArrayInputStream(request);
            BufferedReader br=new BufferedReader(new InputStreamReader(bais));
            String line=null;
            while((line=br.readLine()) != null){
                if(line.startsWith("Host:")){
                    logger.debug("找到真实请求服务器地址:{}", line);
                    String[] strs=line.split(":");
                    if(strs.length==3){
                        realHost=strs[1].trim();
                        realPort=Integer.parseInt(strs[2].trim());
                    }else if(strs.length==2){
                        realHost=strs[1].trim();
                        logger.info("没有找到端口， 使用默认端口80");
                        realPort=80;
                    }
                    
                    break;
                }
            }
            logger.info("realHost={}, realPort={}", realHost, realPort);
            
            // 请求
            
            Socket proxySocket=new Socket();
            try {
                
                proxySocket.connect(new InetSocketAddress(realHost, realPort));
                
                if(proxySocket.isConnected()){
                    logger.info("已链接真实服务...");
                }
                
                logger.debug("转发请求到真实服务...");
                OutputStream os=proxySocket.getOutputStream();
                os.write(request);
                os.flush();
                
                
                logger.info("读取真实服务返回的内容...");
                InputStream is=proxySocket.getInputStream();
                ByteArrayOutputStream bos=new ByteArrayOutputStream();
                
                int b=-1;
                while ((b=is.read())!=-1){
                    bos.write(b);
                    if(is.available()==0){
                        break;
                    }
                }
                
                logger.debug("读取完成...");
                return bos.toByteArray();
                
            } catch (IOException e) {
                String message="请求真实服务地址出错, host="+realHost+
                    ", port="+realPort+", request="+new String(request);
                logger.error(message,e);
                
                message=message+"\r\n"+ e.toString();
                
                return createErrorResponse(message).getBytes();
            }finally {
                proxySocket.close();
            }

        }
        
        
    }


    
    
    // =========================================================
    private static class TestSocket implements Runnable{ //回复固定的响应， 用于测试
        private Socket socket;
        public TestSocket(Socket socket) {
            this.socket = socket;
        }
        @Override
        public void run() {
            try{
                logger.info("读取请求...");
                InputStream is=socket.getInputStream();
                ByteArrayOutputStream bos=new ByteArrayOutputStream();
                int b=-1;
                while(is.available() != 0 ){
                    b=is.read();
                    bos.write(b);
                }
                logger.debug("输出请求...");
                logger.debug(bos.toString());
                logger.info("回复请求...");
                OutputStream os=socket.getOutputStream();
                //                os.write("来自代理的回复\r\n".getBytes());
                //                os.write(bos.toByteArray());
                //                os.write(CONNECT_OK);
                os.write(createResponse("").getBytes());
                os.flush();
                logger.info("完成...");


                logger.info("关闭连接");
                socket.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    public static String createResponse(String body){
        String prefx="HTTP/1.1 200 OK \n" +
            "Server: Apache-Coyote/1.1 \n" +
            "my-message: this is a message from user login interceptor \n" +
            "Content-Type: application/json \n" +
            "Content-Length: 48 \n" +
            "Date: Tue, 30 Jul 2019 05:26:23 GMT \n" +
            "\n"+
            "{\"age\":11,\"password\":null,\"username\":\"timfruit\"}";
        return prefx;
    }
    
    
    public static String createErrorResponse(String body){
        String prefx="HTTP/1.1 500 Internal Server Error \n" +
            "Server: Apache-Coyote/1.1 \n" +
            "Content-Type: text/plain;charset=utf-8  \n" +
            "Content-Length: {BODY_LENGTH} \n" +
            "\n"+
            "{BODY}";
        
        String  response=prefx.replace("{BODY_LENGTH}",body.length()+"")
            .replace("{BODY}",body);
        
        return response;
    }
    
}
